//
//  rec_audio.c
//  yuanGitFFmpeg
//
//  Created by yuanxuzhen on 2021/3/29.
//

#include "rec_audio.h"
//
//  test_c.c
//  MyFFmpegDemo
//
//  Created by yuanxuzhen on 2021/3/26.
//

void getAudio(){

    //context
    AVFormatContext* format_context = NULL;
    AVCodecContext *codec_ctx = NULL;
    SwrContext *swr_ctx = NULL;


    av_log_set_level(AV_LOG_DEBUG);

    rec_status = 1;


    char* url = "/Users/yuanxuzhen/study/mac/myffmpegdemo1/myffmpegdemo1/output/audio.aac";
    //创建文件
    FILE *out_file = fopen(url, "wb+");
    if(!out_file){
        printf("Error, Failed to open file!\n");
        goto __ERROR;
    }

    //打开设备
    format_context = open_dev();
    if(!format_context){
        printf("Error, Failed to open device!\n");
        goto __ERROR;
    }

    //打开编码器上下文
    codec_ctx = open_coder();
    if(!codec_ctx){
        printf("...");
        goto __ERROR;
    }

    //初始化重采样上下文
    swr_ctx = init_swr();
    if(!swr_ctx){
        printf("Error, Failed to alloc buf in frame!\n");
        goto __ERROR;
    }

    //encode
    read_data_and_encode(format_context, codec_ctx, swr_ctx, out_file);


__ERROR:

    if(format_context){
        avformat_close_input(&format_context);
        format_context = NULL;
    }

    if(swr_ctx){
        swr_free(&swr_ctx);
    }

    if(codec_ctx){
        avcodec_free_context(&codec_ctx);
    }

    if(out_file){
        fclose(out_file);
    }

    av_log(NULL, AV_LOG_DEBUG, "finish!\n");
    return;
}




void set_status(int status){
    rec_status = status;
}

AVCodecContext* open_coder(){
    //打开编码器
    int ret;
    char error[1024] = {0, };
    AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac");

    //        AVCodec *codec =  avcodec_find_encoder(AV_CODEC_ID_AAC);
    //
    //    //创建上下文
    AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);

    codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16; //输入音频的采样率
    codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; //输入音频的通道布局
    codec_ctx->channels = 2; //输入音频的通道个数
    codec_ctx->sample_rate = 44100; //输入音频的采样率

    //bitrate 和profile互斥，bit_rate设置为0后，才会查找profile的值
    codec_ctx->bit_rate = 0; //AAC 128K AAC HE 64K AAC HE V2 32K
    codec_ctx->profile = FF_PROFILE_AAC_HE_V2;

    if((ret = avcodec_open2(codec_ctx, codec, NULL)) < 0){
        av_strerror(ret, error, 1024);
        printf(stderr, "Failed to open audio devices, [%d] %s\n", ret, error);
        return  NULL;
    }

    return codec_ctx;

}

SwrContext* init_swr(){
    SwrContext *swr_ctx = NULL;
    swr_ctx = swr_alloc_set_opts(NULL,
                                 AV_CH_LAYOUT_STEREO,
                                 AV_SAMPLE_FMT_S16,
                                 44100,
                                 AV_CH_LAYOUT_MONO,
                                 AV_SAMPLE_FMT_FLT,
                                 44100,
                                 0,
                                 NULL);
    if(!swr_ctx ){
        return NULL;
    }
    int ret = swr_init(swr_ctx);

    if(ret < 0){
        return NULL;
    }

    return swr_ctx;

}

AVFrame* create_frame(){
    AVFrame *frame = av_frame_alloc(); //其中的buffer才是存着主要的数据
    if(!frame){
        return NULL;
    }
    frame->nb_samples = 512;
    frame->format = AV_SAMPLE_FMT_S16;
    frame->channel_layout = AV_CH_LAYOUT_STEREO;
    av_frame_get_buffer(frame, 0);
    if(!frame->data[0]){
        printf("Error, Failed to alloc buf in frame!\n");
        //内存泄漏
        goto __ERROR;
    }
    return frame;
__ERROR:
    if(frame){
        av_frame_free(&frame);
    }
    return NULL;

}


void encode(AVCodecContext* codec_ctx, AVFrame* frame, AVPacket* pkt, FILE* outFile){
    int ret = 0;
    ret = avcodec_send_frame(codec_ctx, frame);
    while (ret == AVERROR(EAGAIN)) {
        usleep(100);
        return;
    }
    while(ret >= 0){
        ret = avcodec_receive_packet(codec_ctx, pkt);
        if(ret < 0 ){
            if(ret == AVERROR(EAGAIN)){
                usleep(100);
                continue;
            }else if(ret == AVERROR_EOF){
                return;
            }else{
                printf("error encodeing avframe");
                exit(-1);
            }
        }


        fwrite(pkt->data,pkt->size, 1, outFile);
        fflush(outFile);
    }
}


AVFormatContext* open_dev(){
    int ret = 0;
    char error[1024] = {0, };
    AVFormatContext* format_context = NULL ;
    char *devicename=":0";
    AVDictionary *options = NULL;
    avdevice_register_all();
    AVInputFormat * iformat = av_find_input_format("avfoundation");
    ret = avformat_open_input(&format_context, devicename, iformat, &options);
    av_dump_format(format_context, 0, devicename, 0);
    if(ret < 0){
        av_strerror(ret, error, 1024);
        printf(stderr, "Failed to open audio devices, [%d] %s\n", ret, error);
        return NULL;
    };
    return format_context;
}



void read_data_and_encode(AVFormatContext *fmt_ctx, //
                          AVCodecContext *c_ctx,
                          SwrContext* swr_ctx,
                          FILE *outfile){
    AVFrame* frame = NULL;

    int ret = 0;
    AVPacket pkt;
    AVPacket *new_pkt = NULL;
    uint8_t  **src_data = NULL;
    int src_linesize = 0;
    uint8_t  **dst_data = NULL;
    int dst_linesize = 0;


    new_pkt = av_packet_alloc();
    if(!new_pkt){
        goto __ERROR;
    }

    frame = create_frame();
    if(!frame){
        //printf(...)
        goto __ERROR;
    }

    ret = av_samples_alloc_array_and_samples(&src_data,
                                       &src_linesize,
                                       1,
                                       512,
                                       AV_SAMPLE_FMT_FLT,
                                       0);
    if(ret < 0){
        goto __ERROR;
    }


    ret = av_samples_alloc_array_and_samples(&dst_data,
                                       &dst_linesize,
                                       2,
                                       512,
                                       AV_SAMPLE_FMT_S16,
                                       0);
    if(ret < 0){
        goto __ERROR;
    }


    while ((ret = av_read_frame(fmt_ctx, &pkt)) == 0 || ret == -35) {
        if(!rec_status){
            break;
        }
        if(ret == -35){
            usleep(100);
            continue;
        }
        memcpy((void *)src_data[0], (void *)pkt.data, pkt.size);
        swr_convert(swr_ctx, dst_data, 512, (const uint8_t **)src_data, 512);
        memcpy((void *)frame->data[0], (void*)dst_data[0], dst_linesize);
        encode(c_ctx, frame, new_pkt, outfile);
        av_packet_unref(&pkt);
    }


__ERROR:
    //释放 AVFrame 和 AVPacket
    if(frame){
        av_frame_free(&frame);
    }

    if(new_pkt){
        av_packet_free(&new_pkt);
    }

    free_data_4_resample(src_data, dst_data);
}

void free_data_4_resample(uint8_t **src_data, uint8_t **dst_data){
    //释放输入输出缓冲区
    if(src_data){
        av_freep(&src_data[0]);
    }
    av_freep(src_data);

    if(dst_data){
        av_freep(&dst_data[0]);
    }
    av_freep(dst_data);
}








